When limited physical pins are available (e.g., only 4 input data pins), we can use a register file to store multiple 4-bit values and perform a 16-bit + 16-bit addition by combining them into two 16-bit operands.

In this design:


Block Diagram

16-Bit Adder with Registry.png


Verilog Implementation

16-Bit Ripple Carry Adder

module add16(
    input Cin,
    input [15:0] A, B,
    output Cout,
    output [15:0] S
);

    wire RCA4_Cout0, RCA4_Cout1, RCA4_Cout2;
    wire [3:0] S_0, S_1, S_2, S_3;

    RCA4 RCA4_0(.A(A[3:0]),   .B(B[3:0]),   .C_in(Cin),         .Sum(S_0), .C_out(RCA4_Cout0));
    RCA4 RCA4_1(.A(A[7:4]),   .B(B[7:4]),   .C_in(RCA4_Cout0), .Sum(S_1), .C_out(RCA4_Cout1));
    RCA4 RCA4_2(.A(A[11:8]),  .B(B[11:8]),  .C_in(RCA4_Cout1), .Sum(S_2), .C_out(RCA4_Cout2));
    RCA4 RCA4_3(.A(A[15:12]), .B(B[15:12]), .C_in(RCA4_Cout2), .Sum(S_3), .C_out(Cout));

    assign S = {S_3, S_2, S_1, S_0};

endmodule

Register File + 16-Bit Adder

module Reg_Add16(
    input reset, RW, clk,
    input [3:0] Din,
    input [2:0] addr,
    output add_cout,
    output [15:0] add_sout,
    output [3:0] read_value
);

    wire [7:0] Decoder_out;
    wire [7:0] reg_en;
    reg [3:0] regfile[0:7];

    // Address Decoder
    Decoder3to8 Decoder0(.Din(addr), .Dout(Decoder_out));

    assign reg_en = (RW) ? 8'd0 : Decoder_out;

    // Register write logic
    always @(posedge clk or negedge reset) begin
        if (!reset) begin
            regfile[0] <= 4'd0;
            regfile[1] <= 4'd0;
            regfile[2] <= 4'd0;
            regfile[3] <= 4'd0;
            regfile[4] <= 4'd0;
            regfile[5] <= 4'd0;
            regfile[6] <= 4'd0;
            regfile[7] <= 4'd0;
        end
        else begin
            regfile[0] <= (reg_en[0]) ? Din : regfile[0];
            regfile[1] <= (reg_en[1]) ? Din : regfile[1];
            regfile[2] <= (reg_en[2]) ? Din : regfile[2];
            regfile[3] <= (reg_en[3]) ? Din : regfile[3];
            regfile[4] <= (reg_en[4]) ? Din : regfile[4];
            regfile[5] <= (reg_en[5]) ? Din : regfile[5];
            regfile[6] <= (reg_en[6]) ? Din : regfile[6];
            regfile[7] <= (reg_en[7]) ? Din : regfile[7];
        end
    end

    // Concatenate 4-bit registers into 16-bit inputs
    wire [15:0] add_in_A = {regfile[3], regfile[2], regfile[1], regfile[0]};
    wire [15:0] add_in_B = {regfile[7], regfile[6], regfile[5], regfile[4]};

    // 16-bit adder instance
    add16 add16_0(.A(add_in_A), .B(add_in_B), .S(add_sout), .Cin(1'b0), .Cout(add_cout));

    // Read selected register
    assign read_value = regfile[addr];

endmodule


Integration with Debounce Button & Seven-Segment Display

module RA16_display(
    input reset, btn, clk, RW,
    input [2:0] addr,
    input [3:0] data,
    output add_cout,
    output [3:0] Sout0, Sout1, Sout2, Sout3, read_value
);

    wire DC_clk;
    wire [15:0] add_result;

    // Debounce Button (generates clean clock pulse)
    Debounce_Circuit DC0(.Din(btn), .clk(clk), .reset(reset), .Dout(DC_clk));

    // Register + Adder
    Reg_Add16 RA16(
        .reset(reset),
        .Din(data),
        .addr(addr),
        .RW(RW),
        .clk(DC_clk),           // <--- use debounced button as clock
        .add_sout(add_result),
        .add_cout(add_cout),
        .read_value(read_value)
    );

    // Display output on four 7-segment displays
    Seven_Segment SS0(.Din(add_result[3:0]),   .Dout(Sout0));
    Seven_Segment SS1(.Din(add_result[7:4]),   .Dout(Sout1));
    Seven_Segment SS2(.Din(add_result[11:8]),  .Dout(Sout2));
    Seven_Segment SS3(.Din(add_result[15:12]), .Dout(Sout3));

endmodule